package fox.framework.rpc.context;

import fox.framework.rpc.client.AbstractRpcClient;
import fox.framework.rpc.client.DefaultRpcClient;
import fox.framework.rpc.client.RpcRegister;
import fox.framework.rpc.client.invocation.ConsumeInvoker;
import fox.framework.rpc.client.invocation.proxy.DefaultProxyFactory;
import fox.framework.rpc.client.invocation.proxy.RpcProxyFactory;
import fox.framework.rpc.client.message.RpcClientRequestInterceptor;
import fox.framework.rpc.client.node.rule.RuleFactory;
import fox.framework.rpc.context.definition.RpcDefinition;
import fox.framework.rpc.context.event.RpcEventListener;
import fox.framework.rpc.context.event.RpcEventPublisher;
import fox.framework.rpc.context.generator.name.DefaultRpcNameGenerator;
import fox.framework.rpc.context.generator.name.RpcNameGenerator;
import fox.framework.rpc.context.order.Order;
import fox.framework.rpc.context.processor.RpcApplicationProcessor;
import fox.framework.rpc.converter.RpcMessageConverter;
import fox.framework.rpc.converter.RpcMessageConverters;
import fox.framework.rpc.endpoint.RpcEndPoint;
import fox.framework.rpc.endpoint.netty.NettyEndpoint;
import fox.framework.rpc.server.dispatcher.DefaultRequestDispatcher;
import fox.framework.rpc.server.dispatcher.RpcRequestDispatcher;
import fox.framework.rpc.server.dispatcher.invoke.ProvideInvoker;
import fox.framework.rpc.server.dispatcher.router.RpcRouter;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author cuichao
 * @Description: ConfigurableRpcApplicationContext
 * @Date: create in 2021/1/7 21:22
 */
public abstract class ConfigurableRpcApplicationContext implements RpcApplicationContext {

    private String applicationName;
    /**
     * 全局Rpc传输协议
     */
    private String globalProtocol;
    /**
     * Rpc服务绑定地址
     */
    private String bind;
    /**
     * Rpc服务绑定的端口号
     */
    private int port;
    /**
     * 全局转换器名称
     */
    private String globalConverterName;
    /**
     * 默认分组
     */
    private String globalGroup;
    /**
     * rpc应用配置类
     */
    private RpcApplicationConfigurer configurer;
    /**
     * 发送器
     */
    private RpcEndPoint endpoint;
    /**
     * rpc客户端
     */
    private AbstractRpcClient client;
    /**
     * rpc分发器
     */
    private RpcRequestDispatcher dispatcher;
    /**
     * Rpc注册监听器
     */
    private RpcRegister register;
    /**
     * Rpc路由
     */
    private RpcRouter router;
    /**
     * 负载均衡控制器
     */
    private RuleFactory ruleFactory;
    /**
     * 默认消息转换器
     */
    private RpcMessageConverter defaultConverter;
    /**
     * Rpc消息转换器
     */
    private RpcMessageConverters converters;
    /**
     * 代理工厂
     */
    private RpcProxyFactory proxyFactory = new DefaultProxyFactory();
    /**
     * Rpc-name生成器
     */
    private RpcNameGenerator nameGenerator = new DefaultRpcNameGenerator();
    /**
     * Rpc服务执行器
     */
    private List<ProvideInvoker> provideInvokers = new ArrayList<>();
    /**
     * Rpc客户端请求拦截器
     */
    private List<RpcClientRequestInterceptor> interceptors = new ArrayList<>();
    /**
     * Rpc消费执行器
     */
    private List<ConsumeInvoker> consumeInvokers = new ArrayList<>();
    /**
     * Rpc事件监听器列表
     */
    private Set<RpcEventListener> rpcEventListeners = new HashSet<>();
    /**
     * 获得Rpc应用配置
     *
     * @return
     */
    protected abstract RpcApplicationConfigurer getRpcApplicationConfigure();
    /**
     * 获得事件发布器
     *
     * @return
     */
    protected abstract RpcEventPublisher getRpcEventPublisher();
    /**
     * 获得rpc注册器
     *
     * @return
     */
    protected abstract RpcDefinitionRegister getRpcDefinitionRegister();


    @Override
    public abstract ConfigurableRegisteredRpcObjectFactory getObjectFactory();

    @Override
    public Object getObject(String name) {
        return getObjectFactory().getObject(name);
    }

    @Override
    public <T> T getObject(Class<T> cls) {
        return getObjectFactory().getObject(cls);
    }


    protected void initWithConfig(RpcApplicationConfigurer configurer) {
        this.configurer = configurer;
        applicationName = configurer.getApplicationName();
        bind = configurer.getBind();
        port = configurer.getPort();
        globalGroup = configurer.getGlobalGroup();
        globalProtocol = configurer.getGlobalProtocol();
        globalConverterName = configurer.getGlobalConverterName();
        register = configurer.getRegister();
        ruleFactory = configurer.getGlobalRuleFactory();
        provideInvokers.addAll(configurer.getProvideInvokers());
        consumeInvokers.addAll(configurer.getConsumeInvokers());
        rpcEventListeners.addAll(configurer.getRpcEventListeners());
        interceptors.addAll(configurer.getClientRequestInterceptors());
        converters = new RpcMessageConverters(configurer.getRpcMessageConverter());
    }


    protected void loadWithConfig() {
        initWithConfig(getRpcApplicationConfigure());
        //configRpcRegister
        configRpcRegister();
        //configServer
        configRpcServer();
        //configEndpoint
        configEndpoint();
        //configRpcClient
        configRpcClient();
        //configObjectFactory
        configObjectFactory();
    }

    protected void configRpcRegister() {
        //nothing to do
    }

    protected void configRpcClient() {
        client = new DefaultRpcClient(bind, port);
        client.setRpcRegister(register);
        client.setEndpoint(endpoint);
        client.setGlobalRpcProtocol(globalProtocol);
        client.setDefaultConverter(getDefaultConverter());
        client.setMessageConverters(converters);
        client.setDefaultRuleFactory(ruleFactory);
        client.refreshRpcRequestInterceptor(getClientRequestInterceptor());
    }

    protected void configRpcServer(){
        router = new RpcRouter();
        List<ProvideInvoker> provideInvokers = registerProvideInvokers();
        dispatcher = new DefaultRequestDispatcher(converters, router, provideInvokers);
    }


    protected void configEndpoint() {
        endpoint = new NettyEndpoint(bind, port);
        endpoint.setRequestDispatcher(dispatcher);
    }


    protected void configObjectFactory(){
        ConfigurableRegisteredRpcObjectFactory factory = getObjectFactory();
        factory.setRpcClient(client);
        factory.setProxyFactory(proxyFactory);
        factory.setNameGenerator(nameGenerator);
        factory.setUnRegisteredConsumerInvokers(consumeInvokers);
    }


    /**
     * 启动客户端
     *
     * @throws Exception
     */
    protected void enableRpcClient(List<RpcDefinition> definitions) throws Exception {
        client.setRpcDefinitions(definitions);
        client.run();
    }


    @Override
    public String name() {
        return applicationName;
    }

    protected RpcEndPoint getEndpoint() {
        return this.endpoint;
    }

    protected AbstractRpcClient getClient() {
        return client;
    }

    protected RpcRegister getRpcNodeRegister() {
        return register;
    }

    protected RpcRouter getRouter() {
        return this.router;
    }

    @Override
    public int getPort() {
        return this.port;
    }

    @Override
    public String getHost() {
        return this.bind;
    }

    @Override
    public String getGlobalProtocol() {
        return globalProtocol;
    }

    @Override
    public String getGlobalGroup() {
        return globalGroup;
    }

    @Override
    public String getDefaultConverterName() {
        return globalConverterName;
    }

    @Override
    public RpcNameGenerator getRpcNameGenerator() {
        return nameGenerator;
    }


    protected RpcMessageConverter getDefaultConverter() {
        if (defaultConverter != null) {
            return defaultConverter;
        }
        defaultConverter = converters.get(globalConverterName);
        return defaultConverter;
    }

    @Override
    public RuleFactory getGlobalRuleFactory() {
        return ruleFactory;
    }

    protected RpcProxyFactory getGlobalProxyFactory(){
        return proxyFactory;
    }

    protected List<ProvideInvoker> getProvideInvokers() {
        return this.provideInvokers;
    }

    protected List<RpcClientRequestInterceptor> getClientRequestInterceptor() {
        return this.interceptors;
    }

    protected Set<RpcEventListener> getRpcEventListeners() {
        return this.rpcEventListeners;
    }

    protected List<ConsumeInvoker> getConsumeInvokers() {
        return this.consumeInvokers;
    }


    protected List<RpcApplicationProcessor> getUnRegisteredApplicationProcessors() {
        return configurer.getApplicationProcessors();
    }

    /**
     * 注册服务端执行器
     * @return
     */
    private List<ProvideInvoker> registerProvideInvokers(){
        List<ProvideInvoker> registered = new ArrayList<>();
        List<ProvideInvoker> ordered = new ArrayList<>();
        List<ProvideInvoker> nonOrdered = new ArrayList<>();
        for (ProvideInvoker provideInvoker : getProvideInvokers()) {
            if(provideInvoker instanceof Order){
                ordered.add(provideInvoker);
            }else {
                nonOrdered.add(provideInvoker);
            }
        }
        Order.sort(ordered);
        registered.addAll(ordered);
        registered.addAll(nonOrdered);
        return registered;
    }

}
